package net.njcp.icodes.util;

/**
 * @author 李志鹏
 * @date 2019/9/19 17:18
 * @Disc edmi数据的精度解析
 **/
public class IEEE754 {

    //当是单精度浮点型时
    private static boolean isDouble = false;
    private static int zsLength = 9;
    private static int zsValue = 127;

    public static void main(String[] args) {
//        String f = toHex(0.625,false);
//        System.out.println(f);
//        double h =IEEE754.toValue(f);
//
//        System.out.println(h);
//
//
//        f = toHex(0.7898164729,true);
//        h =IEEE754.toValue(f);
//        System.out.println(f);
//        System.out.println(h);

//        System.out.println(toHex(40469.3847110022,true));
        System.out.println(toValue("40 E3 C0 89 D4 5C D1 80".replace(" ","")));
    }

    public static String toHex(double value,boolean isDouble) {
        if (value==0)
            return isDouble?"0000000000000000":"00000000";
        if(isDouble){
            IEEE754.isDouble = isDouble;
            zsLength =12;
            zsValue=1023;
        }else {
            zsLength = 9;
            zsValue = 127;
        }

        //符号位
        String sign = value > 0 ? "0" : "1";

        //去正数
        double f = Math.abs(value);

        //整数部分
        int fz = (int) Math.floor(f);
        //整数部分二进制
        String fzBin = Integer.toBinaryString(fz);
        int fzLength = fzBin.equals("0")?0:fzBin.length();

        //小数部分，格式： 0.02
        double ff = f-fz;
        //小数部分二进制
        String ffBin = toBin(ff)+"0";

        if(fzLength==0){
            int i=0;
            char c =ffBin.charAt(0);
            while (c=='0'){
                c =ffBin.charAt(++i);
            }
            fzLength = fzLength-i;
            ffBin = ffBin.substring(++i);
        }



        //指数
        String zsBin = Integer.toBinaryString(fzLength-1+zsValue);
        String zsBin0 = addZero(zsBin, zsLength -1,true);

        //尾数位
        String m = fzBin.substring(1) + ffBin;
        String result = sign + zsBin0 + m;
        result =isDouble?addZero(result,64):addZero(result,32);
        return Long.toHexString(Long.valueOf(result,2));
    }

    public static double toValue(String hex) {
        isDouble = hex.length()==16;
        if(isDouble){
            zsLength =12;
            zsValue=1023;
        }else {
            zsLength = 9;
            zsValue = 127;
        }

        long value =Long.parseLong(hex,16);
        if(value==0)
            return 0;

        String bin = Long.toBinaryString(Long.valueOf(hex,16));
        bin =isDouble?addZero(bin,64,true):addZero(bin,32,true);
        //标志位
        String sign = bin.substring(0,1);
        //指数
        int zs;
        //整数
        double fz;
        //小数
        String ffStr = null;

        zs = Integer.valueOf(bin.substring(1, zsLength), 2) - zsValue;
        if (zs < 0) {
            fz = 0 + Math.pow(2, zs);
            ffStr = bin.substring(zsLength);
        } else {
            fz = Integer.valueOf(1 + bin.substring(zsLength, zsLength + zs), 2);
            ffStr = bin.substring(zsLength + zs);
            zs = 0;
        }

        for(int i=0;i<ffStr.length();i++){
            char a = ffStr.charAt(i);
            if(a=='1'){
                fz = fz+Math.pow(2,-i-1+zs);
            }
        }
        return fz;
    }

    private static String addZero(String str,int size){
        return addZero(str,size,false);
    }

    private static String addZero(String str,int size,boolean isStart){
        if(str.length()>size){
            return str.substring(0,size);
        }else if(str.length()==size){
            return str;
        }else {
            StringBuilder s = new StringBuilder(str);
            while (s.length()<size){
                if(isStart){
                    s.insert(0,"0");
                }else {
                    s.append("0");
                }

            }
            return s.toString();
        }
    }



    private static String toBin(double f) {
        StringBuilder result = new StringBuilder();
        int MAX = isDouble?52:24;

        int bits = 0;
        while (f != -1 && bits < MAX) {
            f = calc(f, result);
            bits++;
        }
        return result.toString();
    }

    private static double calc(double f, StringBuilder result) {
        if (f == 0||f>1)
            return -1;
        double t = f * 2;
        if (t >= 1) {
            result.append("1");
            return t - 1;
        } else {
            result.append("0");
            return t;
        }
    }

}
